package com.jianbo.proxy.core;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

import org.smartboot.http.common.enums.HttpStatus;
import org.smartboot.http.common.utils.StringUtils;
import org.smartboot.http.server.HttpRequest;
import org.smartboot.http.server.HttpResponse;
import org.smartboot.http.server.impl.HttpRequestImpl;
import org.smartboot.http.server.impl.Request;

import com.jianbo.proxy.Start;
import com.jianbo.proxy.conf.jsconfig.ProxyConfig;
import com.jianbo.proxy.entity.HttpResponseMiddle;
import com.jianbo.proxy.entity.ProxyUnit;
import com.jianbo.proxy.util.ByteUtil;
import com.jianbo.proxy.util.Context;
import com.jianbo.proxy.util.Debug;
import com.jianbo.proxy.util.HttpUtil;
import com.jianbo.proxy.util.HttpUtil.HttpResult;
import com.jianbo.proxy.util.IoUtil;
import com.jianbo.proxy.util.RegUtil;

public class ProxyWeb implements Web {
    
    private ProxyConfig proxyConf;

    public void setProxyConf(ProxyConfig proxyConf) {
        this.proxyConf = proxyConf;
    }

    @Override
    public boolean handle(String path, HttpRequest request, HttpResponseMiddle response) throws Exception {
        try {
            Map<String, ProxyUnit> conf = proxyConf.getConf();

            String fullPath = path;

            // 匹配时附带请求参数
            if(StringUtils.isNotBlank(request.getQueryString())) {
                fullPath = fullPath + "?" + request.getQueryString();
            }

            Debug.info("ProxyWeb full path", fullPath);

            for(String mappingUrl : conf.keySet()) {
                // Debug.info("Wait mappingUrl", mappingUrl);

                ProxyUnit unit = conf.get(mappingUrl);
                if(fullPath.startsWith(mappingUrl)) {
                    // 匹配成功
                    // 发起代理请求
                    Map<String, String> rewrite = unit.getPathRewrite();
                    String requestPath = fullPath;
                    
                    if(rewrite != null) {
                        for(String replace : rewrite.keySet()) {
                            // if(path.matches(replace)) {
                            if(RegUtil.match(fullPath, replace)) {
                                requestPath = fullPath.replaceFirst(replace, rewrite.get(replace));
                            }
                            break;
                        }
                    }
                    // 循环调用校验
                    if(unit.getTarget().endsWith(":" +String.valueOf(Start.port))) {
                        if(requestPath.equals(fullPath)) {
                            throw new RuntimeException("循环调用：" + fullPath);
                        }
                    }
                    String requestUrl = unit.getTarget() + requestPath;
                    // Debug.info("requestPath:" + requestPath);
                    Debug.info("requestUrl:" + requestUrl);

                    // if(StringUtils.isNotBlank(request.getQueryString())) {
                    //     requestUrl = requestUrl + "?" + request.getQueryString();
                    // }
                    // Debug.info("requestUrl", requestUrl);
                    
                    Collection<String> headNames = request.getHeaderNames();
                    Map<String, String> headerMap = new LinkedHashMap<>();
                    for(String head : headNames) {
                        String value = request.getHeader(head);
                        headerMap.put(head, value);
                    }
                    // Debug.info("requestHeader", headerMap);
                    // Debug.info("requestLength:", request.getContentLength());
                    InputStream in = request.getInputStream();
                    
                    byte[] bytes = IoUtil.read(in);
                    
                    if(request instanceof HttpRequestImpl) {
                        HttpRequestImpl impl = (HttpRequestImpl)request;
                        Request orequest = impl.getRequest();
                        
                        // ByteBuffer buffer = orequest.getAioSession().readBuffer();
                        // FixedLengthFrameDecoder decoder = new FixedLengthFrameDecoder(request.getContentLength());
                        // decoder.decode(buffer);
                        // bytes = decoder.getBuffer().array();

                        if(orequest.getFormUrlencoded() != null) {
                            String requesData = orequest.getFormUrlencoded();
                            bytes = ByteUtil.bytes(requesData);
                        }
                    }

                    // String requestStr = new String(bytes);
                    // Debug.info("requestBody:" + requestStr);
                    String requestMethod = request.getMethod();
                    // Debug.info("requestMethod:" + requestMethod);
                    Debug.info("requestUrl:" + requestUrl);
                    // Debug.info("requestBytesLength:" + bytes.length);
                    
                    // requestUrl = requestUrl.replace("10.13.1.235:8090", "localhost:6667");
                    HttpResult httpResult = HttpUtil.doRequest(requestUrl, requestMethod, bytes, headerMap);
                    // Debug.info("responseLength:" + httpResult.getResponse().length);

                    // Debug.info("response length:" + httpResult.getResponse().length);
                    int code = httpResult.getResponseCode();
                    if(code == 404) {
                        return false;
                    }

                    CacheWeb cacheWeb = Context.get(CacheWeb.class);
                    cacheWeb.staticCache(path, httpResult);
                    
                    setResponse(response, httpResult);
                    return true;
                }
            }
            return false;
        } catch (Exception e) {
            throw new RuntimeException("proxyError", e);
        }
    }
    
    // 响应
    private void setResponse(HttpResponseMiddle response, HttpResult httpResult) throws IOException {
        response.setHttpStatus(HttpStatus.valueOf(httpResult.getResponseCode()));
        Map<String, String> header = httpResult.getResponseHeader();
        for(String key : header.keySet()) {
            String value = header.get(key);
            response.setHeader(key, value);
        }
        byte[] responseBytes = httpResult.getResponse();
        if(responseBytes != null) {
            response.write(responseBytes);
        }
    }

    public void error(HttpResponse response) throws IOException {
        response.setHttpStatus(HttpStatus.FORBIDDEN);
        response.getOutputStream().write("proxy error".getBytes());
    }
}
